using UnityEngine;
using System.Collections;
using System;

public class HerderBehaviourScript : MonoBehaviour 
{
	private static HerderBehaviourScript captain;
	
	private GameObject laser;
	private const float laserDamage = 20.0f; // Energy drain per second
	private const float attackRange = 100.0f; //was 300

	private ArrayList agents;
	
	private int captain_num = 1;
	public static int herders = 0;
	public int herder_num = 0;

	
    private const float convergeRange = 900.0f;
	
	//Herder Physics constants 	
	// Motion Constants
	private const float maxTorque = 18000.0f;
	private const float maxForwardForce = 350.0f;
	private const float distanceOfMaxForce = 100.0f;
	private const float angleOfMaxTorque = 20.0f;
	
	private const float angularDrag = 10.0f;
	private const float drag = 6.0f;
	
	// Collision Constants
	private const float antennaAngle = 120.0f;
	private const int antennaNumOfRays = 4;
	private const float antennaLengthMin = 85.0f;
	private const float antennaLengthVelocityFactor = 0.5f;
	private const int antennaSweepDivisions = 14;
	private const float antennaSweepAngle = 280.0f; 
	//End Herder Physics constants 	
	
	// a reference to the state machine
	HerderStateMachineScript herderStateMachineScript;

	PhysicsObject physicsObject;
	
	//current state should init to Default
	public HerderStateMachineScript.State currentState = HerderStateMachineScript.State.Herd;
	
	// Use this for initialization
	public void Start () 
	{
		increment_herder_num();		
		print("Start the herder num : " + herder_num);
		
		if(herder_num == captain_num)
		{
			captain = this;
		}		
		
		//grab ref to the state machine
		herderStateMachineScript = (HerderStateMachineScript)(GameObject.FindWithTag("Player").GetComponent("HerderStateMachineScript"));
		this.agents = (((GameController)GameObject. FindWithTag("GameController").GetComponent("GameController")).getAgents());
		
		gameObject.AddComponent("PhysicsObject");
		physicsObject = (PhysicsObject)gameObject.GetComponent("PhysicsObject");
		physicsObject.init();
		physicsObject.setMass(0.5f);
		physicsObject.SetValues(maxTorque, maxForwardForce, distanceOfMaxForce,
			 angleOfMaxTorque, angularDrag, drag,
			 antennaAngle, antennaNumOfRays, antennaLengthMin,
			 antennaLengthVelocityFactor, antennaSweepDivisions, antennaSweepAngle);
			 
		laser = new GameObject("Herder Laser"); 
		laser.AddComponent("LineRenderer");
		laser.renderer.material.shader = Shader.Find("Particles/Additive");
		laser.renderer.enabled = false;
		laser.renderer.material.mainTexture = (Texture)Resources.Load("Scripts/Herder/laserbw3");
		LineRenderer lineRender = (LineRenderer)laser.GetComponent("LineRenderer");	
		lineRender.SetWidth(1.0f, 50.0f);	
		lineRender.SetVertexCount(2);
		lineRender.SetColors(new Color(1.0f, 0.0f, 0.0f, 1.0f), new Color(0.0f, 0.0f, 1.0f, 1.0f));
		
		gameObject.collider.material.dynamicFriction = 0.0f;
		gameObject.collider.material.staticFriction = 0.0f;
	}
	
	public void setLaserEnabled(bool state)
	{
		if (state == true)
		{
			laser.renderer.enabled = true;	
		}else
		{
			laser.renderer.enabled = false;	
		}
	}
	
	public void setLaserTarget(Vector3 target)
	{
		LineRenderer lineRender = (LineRenderer)laser.GetComponent("LineRenderer");	
		lineRender.SetPosition(0, getPosition());
		lineRender.SetPosition(1, target);
	}
	
	public AgentBehaviourScript getClosestAgent()
	{
		float closestDist = -1.0f;
		AgentBehaviourScript returnAgent = null;
		foreach (AgentBehaviourScript agent in agents) 
		{
			if (Vector3.Distance(getPosition(), agent.getPosition()) < closestDist || closestDist < 0)
		    {
		    	closestDist = Vector3.Distance(getPosition(), agent.getPosition());
		    	returnAgent = agent;
			}
        }			
		return returnAgent;	
	}
	
	public int getNumHerders()
	{
		return herders;	
	}
	
	public PhysicsObject getPhysicsObject()
	{
		return physicsObject;	
	}
	
	public void increment_herder_num()
	{
		herder_num = herders + 1;	
		herders = herders + 1;
	}
	
	public void Update ()
	{	
		RaycastHit hit = new RaycastHit();
		AgentBehaviourScript agentTarget = getClosestAgent();
		Vector3 localDir = -((transform.localPosition - agentTarget.getPosition()).normalized);
		
		setLaserTarget(getClosestAgent().getPosition());
		
		//draw local to local
		Debug.DrawRay(transform.localPosition, localDir * attackRange, Color.green);
		
		setLaserEnabled(false);	
		Ray ray = new Ray(transform.localPosition, localDir);
		bool didHit = Physics.Raycast(ray, out hit, attackRange);
		if ( didHit ) {
			String tmp = hit.collider.gameObject.name;
			if ( tmp.Contains("Agent") && hit.distance < attackRange )
			{
				setLaserTarget(getClosestAgent().getPosition());
				setLaserEnabled(true);
				agentTarget.removeEnergy( Time.deltaTime * laserDamage );
			}
		} 
		
	}	
	
	// Update is called once every physics time step
	public void FixedUpdate () 
	{

		// Captain herder - Use Mouse 
		//get the the mouse position from pixel space into world space
		/*
		if(isCaptain())
		{
			Vector3 mouseWorldPos = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, 
																			Input.mousePosition.y, 
																		Camera.main.nearClipPlane));
			setDestination(new Vector3(mouseWorldPos.x, this.transform.position.y, mouseWorldPos.z));
			// Update what the captian would like the hearders to do
			(GetComponent("CircleBehaviour") as CircleBehaviour).updateCaptainsOrders(this as HerderBehaviourScript);
		}
		else
		*/
		{
			// create other herders
			currentState = herderStateMachineScript.run(this);
		}	
		physicsObject.updatePhysics();
		
	}	

	/*
	public Vector3 getHerderPosition ()
	{
		return herderBehaviourScript.transform.position;	
	}
	*/
	
	/*
	public double getDistanceToHerder ()
	{
		return (herderBehaviourScript.transform.position - this.transform.position).magnitude;
	}
	*/
	
	public void ChangeColour (Color targetColour)
	{
		renderer.material.color = targetColour;
	}
	

	// Get the converge range
	private float getConvergeRange()
	{
		return convergeRange;
	}
	
	
	// returns true if the captain is in range
	public bool isCaptainInRange()
	{
		if(herder_num != captain_num)
		{
			// return false if there are not any herders
			try
			{
				float captain_dist = Vector3.Distance(getPosition(), captain.getPosition());
				return (captain_dist < getConvergeRange());
			}
			catch
			{
				return true;
			}
		}
		
		return false;
	}
	
	
	public Vector3 get_captain_position()
	{
		return captain.getPosition();
	}
	
	public float get_captain_distance()
	{
		return Vector3.Distance(getPosition(), captain.getPosition());
	}
	
	public bool isCaptain()
	{
		return (this == captain);	
	}
	
	public HerderBehaviourScript getCaptain()
	{
		return captain;	
	}	
	
	public Vector3 getPosition ()
	{
		return rigidbody.transform.position;
	}
	
	public void setDestination(Vector3 position)
	{
		physicsObject.setDestination(position);
	}
	
	public Vector3 getDestination()
	{
		return physicsObject.getDestination();
	}
	

}
